package com.wechat.page.chat.message;

import org.controlsfx.glyphfont.FontAwesome;
import org.springframework.beans.factory.annotation.Autowired;

import com.swak.entity.YesNo;
import com.swak.fx.support.AbstractComp;
import com.swak.fx.support.AbstractPage;
import com.swak.fx.support.Display;
import com.swak.fx.support.FXMLView;
import com.swak.fx.support.ui.UI;
import com.swak.fx.support.ui.UIIcon;
import com.swak.fx.support.ui.UIImage;
import com.swak.fx.support.ui.UISpinner;
import com.swak.fx.support.ui.UITextFlow;
import com.wechat.dto.ContactDTO;
import com.wechat.dto.MessageDTO;
import com.wechat.enums.MessageFlag;
import com.wechat.enums.MessageType;
import com.wechat.login.LoginService;
import com.wechat.page.api.MessageApi;
import com.wechat.page.chat.message.msg.FileMsgComp;
import com.wechat.page.chat.message.msg.TextMsgComp;
import com.wechat.page.chat.message.msg.TxtMsgComp;
import com.wechat.page.comps.TextComp;
import com.wechat.page.store.ContactStore;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.text.TextAlignment;

/**
 * 消息的详细信息
 * 
 * @author 618lf
 */
@FXMLView(title = "消息", value = "MessageComp.fxml", css = "MessageComp.css")
public class MessageComp extends AbstractComp implements TextComp {

	private final String NICKNAME_STYLE_CLASS = "message__nickname";
	private final String HEADIMG_STYLE_CLASS = "message__headimg";
	private final String CONTENT_STYLE_CLASS = "message__content";
	private final String STATUS_STYLE_CLASS = "message__status";
	private final String PLACEHOLDER_STYLE_CLASS = "message__placeholder";

	private final String SENDER_STYLE_CLASS = "message__sender";

	private UITextFlow nickname;
	private UIImage headimg;
	private Pane placeholder;

	@Autowired
	private MessageApi messageApi;

	public MessageComp(AbstractPage parent) {
		super(parent);
	}

	@Override
	public void initializeParts() {
		super.initializeParts();
		this.nickname = new UITextFlow();
		this.nickname.setVisible(false);
		this.nickname.setManaged(false);
		this.nickname.getStyleClass().add(NICKNAME_STYLE_CLASS);
		GridPane.setMargin(this.nickname, new Insets(0, 10, 5, 10));

		this.headimg = new UIImage().image(Display.logo());
		this.headimg.setPrefSize(35, 35);
		this.headimg.getStyleClass().add(HEADIMG_STYLE_CLASS);
		// GridPane.setMargin(this.headimg, new Insets(5, 0, 0, 0));

		this.placeholder = new Pane();
		this.placeholder.getStyleClass().add(PLACEHOLDER_STYLE_CLASS);
	}

	@Override
	public void layoutParts() {
		super.layoutParts();

		// 占位
		this.addChild(this.placeholder);
		GridPane.setHgrow(this.placeholder, Priority.ALWAYS);

		// 昵称
		this.addChild(this.nickname);
		GridPane.setColumnSpan(this.nickname, 3);

		// 头像
		this.addChild(this.headimg);
		GridPane.setValignment(this.headimg, VPos.TOP);
		GridPane.setHalignment(this.headimg, HPos.LEFT);
		GridPane.setRowSpan(this.headimg, 2);
	}

	private void layoutParts(boolean isSender) {

		// 样式
		if (isSender) {
			this.root.getStyleClass().add(SENDER_STYLE_CLASS);
		} else {
			this.root.getStyleClass().remove(SENDER_STYLE_CLASS);
		}

		// 占位
		GridPane.setConstraints(this.placeholder, isSender ? 0 : 3, 1);

		// 昵称
		GridPane.setConstraints(this.nickname, isSender ? 0 : 1, 0);
		if (isSender) {
			this.nickname.setTextAlignment(TextAlignment.RIGHT);
		} else {
			this.nickname.setTextAlignment(TextAlignment.LEFT);
		}

		// 头像
		GridPane.setConstraints(this.headimg, isSender ? 3 : 0, 0);

		// 内容
		Node content = this.contentProperty().get();
		if (content != null) {
			GridPane.setConstraints(content, isSender ? 2 : 1, 1);
		}

		// 状态
		Node status = this.statusProperty().get();
		if (status != null) {
			GridPane.setConstraints(status, isSender ? 1 : 2, 1);
		}
	}

	private void layoutContent(Node old, Node content) {
		this.removeChild(old);
		if (content != null) {
			this.addChild(content);
			content.getStyleClass().add(CONTENT_STYLE_CLASS);
			boolean sender = this.senderProperty().get();
			this.layoutParts(sender);
		}
	}

	private void layoutStatus(Node old, Node status) {
		this.removeChild(old);
		if (status != null) {
			this.addChild(status);
			status.getStyleClass().add(STATUS_STYLE_CLASS);
			GridPane.setValignment(status, VPos.CENTER);
			GridPane.setHalignment(status, HPos.LEFT);
			boolean sender = this.senderProperty().get();
			this.layoutParts(sender);
		}
	}

	@Override
	public void setupEventHandlers() {
		super.setupEventHandlers();
		this.root.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
			Node node = (Node) e.getTarget();
			Node status = this.statusProperty().get();
			if (status != null && (status == node || status == node.getParent())) {
				this.sendingProperty().set(true);
			}
		});
	}

	@Override
	public void setupValueChangedListeners() {
		super.setupValueChangedListeners();
		this.messageProperty().addListener((ob, o, n) -> this.onMessageChange(n));
		this.contentProperty().addListener((ob, o, n) -> this.layoutContent(o, n));
		this.statusProperty().addListener((ob, o, n) -> this.layoutStatus(o, n));
		this.senderProperty().addListener((ob, o, n) -> this.layoutParts(n));
		this.sendingProperty().addListener((ob, o, n) -> this.onSendingStatusChange(n));
		this.showNicknameProperty().addListener((ob, o, n) -> {
			this.nickname.setVisible(n);
			this.nickname.setManaged(n);
			if (n) {
				GridPane.setMargin(this.headimg, new Insets(5, 0, 0, 0));
			} else {
				GridPane.setMargin(this.headimg, new Insets(0, 0, 0, 0));
			}
		});
	}

	private void onMessageChange(MessageDTO message) {

		// 是否发送人
		this.senderProperty().set(message.getIsSender() == YesNo.Yes.getType() ? true : false);

		// 昵称
		this.buildNickname(message);

		// 内容
		this.buildContent(message);

		// 状态
		this.buildStatus(message);

		// 图像
		this.buildHeadimg(message);

		// 发送消息
		this.sendMessage(message);
	}

	private void buildNickname(MessageDTO message) {
		String contactID = message.getIsSender() == YesNo.Yes.getType() ? LoginService.login().getId()
				: message.getTalker();
		ContactStore.GetContact(contactID).thenAccept(this::onNickNameLoaded);
	}

	private void onNickNameLoaded(ContactDTO contact) {
		this.$runUI(() -> this.buildTextContent(this.nickname, contact.getNickName()));
	}

	private void buildContent(MessageDTO message) {
		Node content = null;
		MessageType msgType = MessageType.of(message.getMsgType());
		switch (msgType) {
		case Txt:
			content = new TxtMsgComp(message);
			break;
		case Text:
			content = new TextMsgComp(message);
			break;
		case Image:
		case Video:
		case Audio:
		case File:
			content = new FileMsgComp(message);
			break;
		case Link:
		}
		this.contentProperty().set(content);
	}

	private void buildStatus(MessageDTO message) {
		Node status = null;
		if (message.getMsgFlag() != null && MessageFlag.isSending(message.getMsgFlag())) {
			status = new UISpinner();
			((UISpinner) status).setRadius(14);
		} else if (message.getMsgFlag() != null && MessageFlag.isSendFail(message.getMsgFlag())) {
			status = new UIIcon(FontAwesome.Glyph.EXCLAMATION_TRIANGLE);
			((UIIcon) status).Size(22).color(UI.Colors.Warning);
		} else {
			status = null;
		}
		this.statusProperty().set(status);
	}

	private void buildHeadimg(MessageDTO message) {
		String contactID = message.getIsSender() == YesNo.Yes.getType() ? LoginService.login().getId()
				: message.getTalker();
		ContactStore.GetContact(contactID).thenAccept(this::onHeadimgLoaded);
	}

	private void onHeadimgLoaded(ContactDTO contact) {
		Object headimg = contact != null && contact.getHeadimg() != null
				&& contact.getHeadimg().getSmallHeadimgFile() != null ? contact.getHeadimg().getSmallHeadimgFile()
						: Display.logo();
		this.$runUI(() -> this.headimg.nodeProperty().set(headimg));
	}

	private void sendMessage(MessageDTO message) {
		if (message.getMsgFlag() != null && MessageFlag.isUnsend(message.getMsgFlag())) {
			this.sendingProperty().set(true);
		}
	}

	private void onSendingStatusChange(boolean sending) {

		// 非发送中，不用处理
		if (!sending) {
			return;
		}

		// 校验状态 -- 未发送和发送失败（需要点击才能发送）才能发送
		MessageDTO message = this.messageProperty().get();
		if (!(message.getMsgFlag() != null
				&& (MessageFlag.isSendFail(message.getMsgFlag()) || MessageFlag.isUnsend(message.getMsgFlag())))) {
			this.sendingProperty().set(false);
			return;
		}

		// 修改状态
		message.setMsgFlag(MessageFlag.setSendFlag(message.getMsgFlag(), MessageFlag.Sending));
		this.buildStatus(message);

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("[消息] - 发送消息");
		}

		// 发送消息，且等待发送结束后修改状态
		this.$setTimeOut(() -> {
			this.$run(() -> {
				this.messageApi.send(message).whenComplete(this::onSendingComplete);
			});
		}, 200);
	}

	private void onSendingComplete(MessageDTO result, Throwable e) {

		MessageDTO message = this.messageProperty().get();
		if (e == null) {
			message.setMsgFlag(result.getMsgFlag());
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("[消息] - 发送结果 {}", MessageFlag.isSendSuccess(result.getMsgFlag()));
			}
		} else {
			message.setMsgFlag(MessageFlag.setSendFlag(message.getMsgFlag(), MessageFlag.SendFail));
		}

		Display.runUI(() -> {
			this.buildStatus(message);
			this.sendingProperty().set(false);
		});
	}

	// ================================================================================
	// Properties
	// ================================================================================
	private ObjectProperty<Node> statusProperty = new SimpleObjectProperty<>();

	private ObjectProperty<Node> statusProperty() {
		return this.statusProperty;
	}

	private ObjectProperty<Node> contentProperty = new SimpleObjectProperty<>();

	private ObjectProperty<Node> contentProperty() {
		return this.contentProperty;
	}

	private BooleanProperty senderProperty = new SimpleBooleanProperty();

	private BooleanProperty senderProperty() {
		return this.senderProperty;
	}

	private BooleanProperty sendingProperty = new SimpleBooleanProperty();

	private BooleanProperty sendingProperty() {
		return this.sendingProperty;
	}

	// ================================================================================
	// 是否显示：昵称
	// ================================================================================
	private final ObjectProperty<MessageDTO> messageProperty = new SimpleObjectProperty<>();

	public ObjectProperty<MessageDTO> messageProperty() {
		return this.messageProperty;
	}

	private BooleanProperty showNicknameProperty = new SimpleBooleanProperty();

	public BooleanProperty showNicknameProperty() {
		return this.showNicknameProperty;
	}
}
